package cn.wolfcode;

import cn.wolfcode.web.hander.Hander;
import cn.wolfcode.web.hander.IsAdmin;
import org.aspectj.lang.annotation.Aspect;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.*;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

@SpringBootApplication
@MapperScan("cn.wolfcode.mapper")
public class App implements WebMvcConfigurer {

    @Autowired
    private Hander hander;
    @Autowired
    private IsAdmin isAdmin;

    public static void main(String[] args) {
        SpringApplication.run(App.class,args);
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(hander)
                .addPathPatterns("/**")
                .excludePathPatterns("/login.html","/css/**","/img/**","/js/**","/loginEmp");

        registry.addInterceptor(isAdmin)
                .addPathPatterns("/**")
                .excludePathPatterns("/login.html","/css/**","/img/**","/js/**","/loginEmp");
    }






    /**
     * 配置全局事务
     */
    @Aspect
    @Configuration
    public class TransactionManagerConfig {


        private static final int AOP_TIME_OUT = 50000;

        private static final String AOP_POINTCUT_EXPRESSION = "(execution(* cn.wolfcode.service.impl.*ServiceImpl.*(..)))";

        @Autowired
        private PlatformTransactionManager transactionManager;

        @Bean
        public TransactionInterceptor txAdvice(){
            NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();

            /** 只读事务，不做更新操作 注:此事务下做修改操作会报错*/
            RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
            readOnlyTx.setReadOnly(true);
            readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); //支持当前事务；如果不存在，请创建一个新的

            /** 非只读事务 , 如果没有事务,就以非事务执行*/
//        readOnlyTx.setReadOnly(false);
//        readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS); //支持当前事务；如果不存在，则以非事务方式执行。

            /** 事务类型*/
            // readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);//不支持当前交易；而是始终以非事务方式执行。

            /** 当前存在事务就使用当前事务，当前不存在事务就创建一个新的事务 */
            RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute();

            /** 什么异常需要回滚 */
            requiredTx.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
            requiredTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);//支持当前事务；如果不存在，请创建一个新的
            requiredTx.setTimeout(AOP_TIME_OUT);

            Map<String, TransactionAttribute> methodMap = new HashMap<>();


            /** 其他方法无事务，只读 */
            methodMap.put("list*", readOnlyTx);
            methodMap.put("query*", readOnlyTx);
            methodMap.put("get*", readOnlyTx);
            methodMap.put("select*", readOnlyTx);
            methodMap.put("count*", readOnlyTx);

            source.setNameMap(methodMap);

            TransactionInterceptor txAdvice = new TransactionInterceptor(transactionManager, source);
            return txAdvice;
        }

        @Bean(name = "txAdviceAdvisor")
        public Advisor txAdviceAdvisor() {

            AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
            pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
            return new DefaultPointcutAdvisor(pointcut, txAdvice());
        }
    }

}
